/**
    Copyright (c) 2010-2011 yakiimo02
    Distributed under the New BSD License.
    See included license.txt or http://www.yakiimo3d.com/NewBSDLicense.txt
**/

#pragma once

#include "CPU/MandelbrotCPU.h"
#include "DirectCompute/MandelbrotDirectCompute.h"
#include "Cuda/MandelbrotCuda.h"
#include "DataBufferDX11.h"

enum MandelbrotMode 
{
    MANDELBROT_MODE_CPU,                    // use cpu
    MANDELBROT_MODE_DIRECTCOMPUTE,          // use direct compute
    MANDELBROT_MODE_CUDA,                   // use cuda
    MANDELBROT_MODE_NUM
};

/**
    @brief Manages the different Mandelbrot implementations.
    @date  2010/01/31
*/
class MandelbrotMgr
{
public:
    MandelbrotMgr();
    ~MandelbrotMgr();

    HRESULT OnCreateDevice( ID3D11Device* pd3dDevice );
    HRESULT OnResizedSwapChain( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc );
    void    OnFrameRender( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext,
                                  double fTime, float fElapsedTime, void* pUserContext );
    void    OnDestroyDevice();
    
    LRESULT HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

    void    TranslateCenter( const D3DXVECTOR2& vDeltaCenter );
    void    ZoomScale( const float fDeltaScale );
    
    void    SetnMaxIterations( int nMaxIterations );

    inline void SetMode( const MandelbrotMode mode );

    inline D3DXVECTOR2                  GetvCenter() const;
    inline float                        GetfZoomScale() const;
    inline const ConstantBuf*           GetpConstantBuf() const;
    inline MandelbrotMode               GetMode() const { return m_mode; }
    inline DataBufferDX11*              GetpDataBufferDX11() { return &m_dataBufferDX11; }
    inline int                          GetnMaxIterations() const;

protected:
    MandelbrotCPU               m_cpu;                   // cpu
    MandelbrotDirectCompute     m_directCompute;         // directcompute
    MandelbrotCuda              m_cuda;                  // cuda
    MandelbrotBase*             m_pActiveMandelbrot;     // currently selected Mandelbrot implementation

    MandelbrotMode              m_mode;                  // selected Mandelbrot implementation
    DataBufferDX11              m_dataBufferDX11;        // uav, srv stuff
};

extern MandelbrotMgr    g_mandelbrotMgr;


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MandelbrotMgr::SetMode( const MandelbrotMode mode ) 
{ 
    m_mode = mode;
    if( m_mode == MANDELBROT_MODE_CPU ) {
        m_pActiveMandelbrot = &m_cpu;
    }
    else if( m_mode == MANDELBROT_MODE_DIRECTCOMPUTE ) {
        m_pActiveMandelbrot = &m_directCompute;
    }
    else if( m_mode == MANDELBROT_MODE_CUDA ) {
        m_pActiveMandelbrot = &m_cuda;
    }
}

D3DXVECTOR2 MandelbrotMgr::GetvCenter() const 
{
    return m_pActiveMandelbrot->GetvCenter();
}

float MandelbrotMgr::GetfZoomScale() const 
{ 
    return m_pActiveMandelbrot->GetfZoomScale();
}

const ConstantBuf* MandelbrotMgr::GetpConstantBuf() const
{
    return m_pActiveMandelbrot->GetpConstantBuf();
}

int MandelbrotMgr::GetnMaxIterations() const
{
    return m_pActiveMandelbrot->GetnMaxIterations();
}